package it.unicam.cs.cosy.bioshape.gui;

import hermesV3.util.HermesLogger;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.EmptyBorder;

/**
 * Loads the options which can be altered by the user.
 * 
 * @author Federico Buti
 */
public class Options extends JDialog {

	/** Auto-generated serial ID */
	private static final long serialVersionUID = 4092766236559741L;
	private JCheckBox checkBox;

	/**
	 * Builds the option dialog.
	 * 
	 * @param owner
	 *            Application {@code Frame} controlling the window.
	 */
	public Options(Frame owner) {
		super(owner);
		initComponents();
	}

	private void buttonPressed(ActionEvent e) {
		String command = e.getActionCommand();
		if (command.equalsIgnoreCase("cancel")) {
			this.setVisible(false);
			return;
		}
		// else...
		try {
			saveUpdatedValues();
		} catch (Exception ex) {
			HermesLogger.log(HermesLogger.ERROR, this.getClass()
					.getSimpleName()
					+ " - Fatal error while saving properties. File not found "
					+ "or output error. The application will be closed.");
			System.exit(1);
		}
		setVisible(false);
	}

	private void initComponents() {
		dialogPane = new JPanel();
		contentPanel = new JPanel();
		label9 = new JLabel();
		separator2 = new JSeparator();
		label1 = new JLabel();
		spinner1 = new JSpinner();
		label2 = new JLabel();
		spinner6 = new JSpinner();
		label3 = new JLabel();
		spinner7 = new JSpinner();
		vSpacer1 = new JPanel(null);
		label8 = new JLabel();
		separator3 = new JSeparator();
		label4 = new JLabel();
		spinner3 = new JSpinner();
		label5 = new JLabel();
		textField1 = new JTextField();
		label6 = new JLabel();
		spinner2 = new JSpinner();
		label10 = new JLabel();
		spinner5 = new JSpinner();
		label7 = new JLabel();
		checkBox = new JCheckBox();
		buttonBar = new JPanel();
		panel1 = new JPanel();
		okButton = new JButton();
		cancelButton = new JButton();

		// ======== this ========
		setTitle("Options");
		Container contentPane = getContentPane();
		contentPane.setLayout(new BorderLayout());

		// ======== dialogPane ========
		{
			dialogPane.setBorder(new EmptyBorder(10, 10, 10, 10));

			dialogPane.setLayout(new BorderLayout());

			// ======== contentPanel ========
			{
				contentPanel.setLayout(new GridBagLayout());
				((GridBagLayout) contentPanel.getLayout()).columnWidths = new int[] {
						0, 0, 0 };
				((GridBagLayout) contentPanel.getLayout()).rowHeights = new int[] {
						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
						0, 0 };
				((GridBagLayout) contentPanel.getLayout()).columnWeights = new double[] {
						0.0, 0.0, 1.0E-4 };
				((GridBagLayout) contentPanel.getLayout()).rowWeights = new double[] {
						0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
						0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0E-4 };

				// ---- label9 ----

				label9.setText("<html><font size=+1><b>General options</b></font>&nbsp;<i><font size=-1>(restart to apply changes)</font></i></html>");
				contentPanel.add(label9, new GridBagConstraints(0, 1, 2, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
				contentPanel.add(separator2, new GridBagConstraints(0, 2, 2, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label1 ----
				label1.setText("Connection timeout (in sec.)");
				label1.setToolTipText("Time out of the connections (in seconds), 0 for unlimited timeout");
				contentPanel
						.add(label1, new GridBagConstraints(0, 4, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));
				contentPanel.add(spinner1, new GridBagConstraints(1, 4, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
				spinner1.setToolTipText("Time out of the connections (in seconds), 0 for unlimited timeout");
				// ---- label2 ----
				label2.setText("Peer connection retries");
				label2.setToolTipText("Peer attempts to contact the GlobalCoordinator, before it throws an error and terminates its execution");
				contentPanel
						.add(label2, new GridBagConstraints(0, 5, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner6 ----
				spinner6.setModel(new SpinnerNumberModel(new Integer(10),
						new Integer(1), null, new Integer(1)));
				spinner6.setToolTipText("Peer attempts to contact the GlobalCoordinator, before it throws an error and terminates its execution");
				contentPanel.add(spinner6, new GridBagConstraints(1, 5, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label3 ----
				label3.setText("Peer connection interval (in sec.)");
				label3.setToolTipText("Time interval between each PeerAgent attempt to contact the GlobalCoordinator");
				contentPanel
						.add(label3, new GridBagConstraints(0, 6, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner7 ----
				spinner7.setModel(new SpinnerNumberModel(new Integer(10),
						new Integer(1), null, new Integer(1)));
				spinner7.setToolTipText("Time interval between each PeerAgent attempt to contact the GlobalCoordinator");
				contentPanel.add(spinner7, new GridBagConstraints(1, 6, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
				contentPanel
						.add(vSpacer1, new GridBagConstraints(0, 7, 1, 4, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- label8 ----
				label8.setText("<html><font size=+1><b>Logger options</b></font>&nbsp;&nbsp;<i><font size=-1>(restart to apply changes)</font></i></html>");
				contentPanel
						.add(label8, new GridBagConstraints(0, 11, 2, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));
				contentPanel.add(separator3, new GridBagConstraints(0, 12, 2,
						1, 0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label4 ----
				label4.setText("Logger type");
				label4.setToolTipText("Type of logger: console logger, file logger or a GUI logger (table) combined with a file logger");
				contentPanel
						.add(label4, new GridBagConstraints(0, 13, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner3 ----
				spinner3.setModel(new SpinnerListModel(new String[] {
						"Console", "File", "Graphic (file)" }) {
					/** Auto-generated serial ID */
					private static final long serialVersionUID = 266256833288199982L;

					{
						setValue("Graphic (file)");
					}
				});
				spinner3.setToolTipText("Type of logger: console logger, file logger or a GUI logger (table) combined with a file logger");
				spinner3.setPreferredSize(new Dimension(110, 28));
				contentPanel.add(spinner3, new GridBagConstraints(1, 13, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label5 ----
				label5.setText("Log filename");
				label5.setToolTipText("Name of the log file generated by the application");
				contentPanel
						.add(label5, new GridBagConstraints(0, 14, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- textField1 ----
				textField1.setText("BioShape");
				textField1
						.setToolTipText("Name of the log file generated by the application");
				contentPanel.add(textField1, new GridBagConstraints(1, 14, 1,
						1, 0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label6 ----
				label6.setText("Log format");
				label6.setToolTipText("GUI and file logs format. It can be as XML or as plain text");
				contentPanel
						.add(label6, new GridBagConstraints(0, 15, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner2 ----
				spinner2.setModel(new SpinnerListModel(new String[] { "xml",
						"simple" }));
				spinner2.setToolTipText("GUI and file logs format. It can be as XML or as plain text");
				contentPanel.add(spinner2, new GridBagConstraints(1, 15, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label10 ----
				label10.setText("Logger counter");
				label10.setToolTipText("Number of log files to be used");
				contentPanel
						.add(label10, new GridBagConstraints(0, 16, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner5 ----
				spinner5.setForeground(Color.black);
				spinner5.setToolTipText("Number of log files to be used");
				spinner5.setModel(new SpinnerNumberModel(new Integer(1),
						new Integer(1), null, new Integer(1)));
				contentPanel.add(spinner5, new GridBagConstraints(1, 16, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));

				// ---- label7 ----
				label7.setText("Log date");
				label7.setToolTipText("Adds the current date in the filename of the log (only for file and GUI loggers)");
				contentPanel
						.add(label7, new GridBagConstraints(0, 17, 1, 1, 0.0,
								0.0, GridBagConstraints.CENTER,
								GridBagConstraints.BOTH,
								new Insets(0, 0, 5, 10), 0, 0));

				// ---- spinner4 ----
				checkBox.setSelected(false);
				checkBox.setToolTipText("Adds the current date in the filename of the log (only for file and GUI loggers)");
				contentPanel.add(checkBox, new GridBagConstraints(1, 17, 1, 1,
						0.0, 0.0, GridBagConstraints.CENTER,
						GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
			}
			dialogPane.add(contentPanel, BorderLayout.WEST);

			// ======== buttonBar ========
			{
				buttonBar.setBorder(new EmptyBorder(12, 0, 0, 0));
				buttonBar.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

				// ======== panel1 ========
				{
					panel1.setLayout(new GridLayout(1, 3, 8, 8));

					// ---- okButton ----
					okButton.setText("Apply");
					okButton.addActionListener(new ActionListener() {
						@SuppressWarnings("synthetic-access")
						@Override
						public void actionPerformed(ActionEvent e) {
							buttonPressed(e);
						}
					});
					panel1.add(okButton);

					// ---- cancelButton ----
					cancelButton.setText("Cancel");
					cancelButton.addActionListener(new ActionListener() {
						@SuppressWarnings("synthetic-access")
						@Override
						public void actionPerformed(ActionEvent e) {
							buttonPressed(e);
						}
					});
					panel1.add(cancelButton);
				}
				buttonBar.add(panel1);
			}
			dialogPane.add(buttonBar, BorderLayout.SOUTH);
		}
		contentPane.add(dialogPane, BorderLayout.CENTER);
		pack();
		setLocationRelativeTo(getOwner());
		setModal(true);
	}

	/**
	 * Loads the current values for the options
	 * 
	 * @throws IOException
	 *             If an error occurs while reading.
	 * @throws FileNotFoundException
	 *             If the specified property file does not exists.
	 */
	void updateValues() throws FileNotFoundException, IOException {
		Properties prop1 = new Properties();
		String home = ((Monitor) getParent()).getHermesHome();
		System.out.println(home);
		FileReader f1 = new FileReader(new File(home + File.separator + "conf"
				+ File.separator + "hermes.properties"));
		System.out.println(f1);
		prop1.load(f1);
		//
		// general
		int value = Integer.parseInt(prop1.get("HERMESNET.TIMEOUT").toString());
		spinner1.setValue(new Integer(value));
		//
		value = Integer.parseInt(prop1.get("BIOSHAPE.PEER_TRIES").toString());
		spinner6.setValue(new Integer(value));
		//
		value = Integer.parseInt(prop1.get("BIOSHAPE.PEER_TIMEOUT").toString());
		spinner7.setValue(new Integer(value));
		//
		// logs
		String logType = prop1.get("HERMES.LOG_CLASS").toString();
		if (logType.contains("GUI"))
			spinner3.setValue("Graphic (file)");
		else if (logType.contains("file"))
			spinner3.setValue("File");
		else
			spinner3.setValue("Console");
		//
		String filename = prop1.get("HERMESFILELOGGER.FILENAME").toString();
		textField1.setText(filename);
		String format = prop1.get("HERMESFILELOGGER.FORMAT").toString();
		spinner2.setValue(format);
		int fileCount = Integer.parseInt(prop1.get("HERMESFILELOGGER.COUNT")
				.toString());
		spinner5.setValue(new Integer(fileCount));
		boolean date = Boolean.parseBoolean(prop1.get("HERMESFILELOGGER.DATE")
				.toString());
		checkBox.setSelected(date);
		//
		f1.close();
	}

	/**
	 * Loads the current values for the options
	 * 
	 * @throws IOException
	 *             If an error occurs while reading.
	 * @throws FileNotFoundException
	 *             If the specified property file does not exists.
	 */
	void saveUpdatedValues() throws FileNotFoundException, IOException {
		Properties prop1 = new Properties();
		String home = ((Monitor) getParent()).getHermesHome();
		FileReader f1 = new FileReader(new File(home + File.separator + "conf"
				+ File.separator + "hermes.properties"));
		prop1.load(f1);
		f1.close();
		//
		// general
		prop1.setProperty("HERMESNET.TIMEOUT", spinner1.getValue().toString());
		//
		prop1.setProperty("BIOSHAPE.PEER_TRIES", spinner6.getValue().toString());
		//
		prop1.setProperty("BIOSHAPE.PEER_TIMEOUT", spinner7.getValue()
				.toString());
		//
		// logs
		String value = spinner3.getValue().toString();
		if (value.contains("Graphic (file)"))
			prop1.setProperty("HERMES.LOG_CLASS",
					"hermesV3.util.loggers.HermesGUILogger");
		else if (value.contains("Console"))
			prop1.setProperty("HERMES.LOG_CLASS",
					"hermesV3.util.loggers.HermesConsoleLogger");
		else
			prop1.setProperty("HERMES.LOG_CLASS",
					"hermesV3.util.loggers.HermesFileLogger");
		//
		prop1.setProperty("HERMESFILELOGGER.FILENAME", textField1.getText());
		prop1.setProperty("HERMESFILELOGGER.FORMAT", spinner2.getValue()
				.toString());

		prop1.setProperty("HERMESFILELOGGER.COUNT", spinner5.getValue()
				.toString());
		prop1.setProperty("HERMESFILELOGGER.DATE",
				new Boolean(checkBox.isSelected()).toString());
		//
		// store
		FileWriter fw1 = new FileWriter(new File(home + File.separator + "conf"
				+ File.separator + "hermes.properties"));
		prop1.store(fw1, null);
		fw1.close();
	}

	private JPanel dialogPane;
	private JPanel contentPanel;
	private JLabel label9;
	private JSeparator separator2;
	private JLabel label1;
	private JSpinner spinner1;
	private JLabel label2;
	private JSpinner spinner6;
	private JLabel label3;
	private JSpinner spinner7;
	private JPanel vSpacer1;
	private JLabel label8;
	private JSeparator separator3;
	private JLabel label4;
	private JSpinner spinner3;
	private JLabel label5;
	private JTextField textField1;
	private JLabel label6;
	private JSpinner spinner2;
	private JLabel label10;
	private JSpinner spinner5;
	private JLabel label7;
	private JPanel buttonBar;
	private JPanel panel1;
	private JButton okButton;
	private JButton cancelButton;
}